#include "target.h"
#include "rightwidget.h"

////////////////////////////////////////////////////////////////////////////////
// TargetManager
TargetManager::TargetManager(const QString &ip, quint16 port,
                             const QString& filePath,QObject *parent)
    : m_ip(ip),m_port(port),m_filePath(filePath),QThread(parent)
{

}

TargetManager::~TargetManager()
{

}

void TargetManager::run()
{
    Target* target=new Target(m_ip,m_port);
    target->init();
    if(!target->isConnected())
    {
        emit sigConnectStatus(false);
        return;
    }

    emit sigConnectStatus(true);

    connect(target,SIGNAL(sigDisconnect()),this,SLOT(processDisconnect()));
    connect(target,SIGNAL(sigData(QByteArray)),this,SLOT(processData(QByteArray)),Qt::DirectConnection);
    connect(this,SIGNAL(sigCommand(QByteArray)),target,SLOT(sendCmd(QByteArray)));

    exec();
    delete target;
    target=NULL;
}

void TargetManager::processDisconnect()
{
    emit sigConnectStatus(false);
}

void TargetManager::processData(QByteArray data)
{
    quint8 code=data.at(0);

    bool commandNotify;

    switch(code)
    {
        case tfcParmReadHardware:
        {
            commandNotify=true;
            m_bcommandStatus=true;
            QByteArray dataTmp=data.mid(1);
            QBuffer bufParm(&(dataTmp));
            bufParm.open(QBuffer::ReadOnly);
            QDataStream ds(&bufParm);

            ds>>ghardware.eth0Mac
              >>ghardware.eth0Ip
              >>ghardware.eth0NetMask
              >>ghardware.eth1Mac
              >>ghardware.eth1Ip
              >>ghardware.eth1NetMask
              >>ghardware.can0Bitrate
              >>ghardware.can1Bitrate
              >>ghardware.switchAddr
              >>ghardware.switchType
              >>ghardware.srl1Bitrate
              >>ghardware.srl1Charbits
              >>ghardware.srl1stopbits
              >>ghardware.srl1Parity
              >>ghardware.srl2Bitrate
              >>ghardware.srl2Charbits
              >>ghardware.srl2stopbits
              >>ghardware.srl2Parity
              >>ghardware.srl3Bitrate
              >>ghardware.srl3Charbits
              >>ghardware.srl3stopbits
              >>ghardware.srl3Parity
              >>ghardware.srl4Bitrate
              >>ghardware.srl4Charbits
              >>ghardware.srl4stopbits
              >>ghardware.srl4Parity;
            break;
        }

        case tfcParmReadDevice:
        {
            commandNotify=true;
            m_bcommandStatus=true;

            QByteArray dataTmp=data.mid(1);
            QBuffer bufParm(&(dataTmp));
            bufParm.open(QBuffer::ReadOnly);
            QDataStream ds(&bufParm);

            qDeleteAll(gPoints);
            gPoints.clear();

            gDevice.clear();

            qint8 mprDevice;
            quint32 deviceCount;
            quint32 deviceId;
            quint32 pointCount;
            quint32 pointType;
            quint32 pointId;
            QString deviceType;

            DevicePoint* point;

            ds>>mprDevice;
            gCanDevice=mprDevice;

            ds>>deviceCount;
            for(quint32 i=0;i<deviceCount;i++)
            {
                ds>>deviceId;
                ds>>deviceType;
                gDevice.insert(deviceId,deviceType);
                point=new DevicePoint;
                ds>>point->lstAi
                    >>point->lstDi
                    >>point->lstPi
                    >>point->lstDo
                    >>point->lstAo
                    >>point->lstAction
                    >>point->lstAlarm;
                /*ds>>pointCount;
                for(quint32 j=0;j<pointCount;j++)
                {
                    ds>>pointType;
                    ds>>pointId;
                    switch(pointType)
                    {
                        case pvAi:
                            point->lstAi.append(pointId);
                            break;

                        case pvDi:
                            point->lstDi.append(pointId);
                            break;

                        case pvPi:
                            point->lstPi.append(pointId);
                            break;

                        case pvDo:
                            point->lstDo.append(pointId);
                            break;

                        case pvAction:
                            point->lstAction.append(pointId);
                            break;

                        case pvAlarm:
                            point->lstAlarm.append(pointId);
                            break;
                    }
                }*/

                gPoints.insert(deviceId,point);
            }
            break;
        }

        case tfcParmReadHy103:
        {
            commandNotify=true;
            m_bcommandStatus=true;

            QByteArray dataTmp=data.mid(1);
            QBuffer bufParm(&(dataTmp));
            bufParm.open(QBuffer::ReadOnly);
            QDataStream ds(&bufParm);

            qDeleteAll(gHy103Cpu);
            gHy103Cpu.clear();

            qint8 mprDevice;
            ds>>mprDevice;

            quint32 cpuCount;
            quint32 pointCount;
            quint32 cpuId;
            quint32 deviceId;
            quint32 pointId;
            quint32 eventSubNumber;
            quint32 eventId;
            quint32 eventType;
            qint8 bNeedAnalysis;
            Hy103Cpu* hy103Cpu;

            ds>>cpuCount;
            for(quint32 i=0;i<cpuCount;i++)
            {
                ds>>cpuId;
                if(mprDevice&&cpuId<=32)
                {
                    m_bcommandStatus=false;
                    m_wait.wakeAll();
                    return;
                }
                hy103Cpu=new Hy103Cpu;
                gHy103Cpu.insert(cpuId,hy103Cpu);
                ds>>hy103Cpu->devId
                    >>bNeedAnalysis
                    >>hy103Cpu->lstAi
                    >>hy103Cpu->lstDi
                    >>hy103Cpu->lstPi
                    >>hy103Cpu->lstDo
                    >>hy103Cpu->lstAo
                    >>hy103Cpu->lstAction
                    >>hy103Cpu->lstAlarm;
                /*
                ds>>pointCount;
                for(quint32 j=0;j<pointCount;j++)
                {
                    ds>>deviceId>>pointId;
                    hy103Cpu->devId=deviceId;
                    hy103Cpu->lstAi.append(pointId);
                }

                ds>>pointCount;
                for(quint32 j=0;j<pointCount;j++)
                {
                    ds>>deviceId>>pointId;
                    hy103Cpu->devId=deviceId;
                    hy103Cpu->lstDi.append(pointId);
                }

                ds>>pointCount;
                for(quint32 j=0;j<pointCount;j++)
                {
                    ds>>deviceId>>pointId;
                    hy103Cpu->devId=deviceId;
                    hy103Cpu->lstPi.append(pointId);
                }

                ds>>pointCount;
                for(quint32 j=0;j<pointCount;j++)
                {
                    ds>>eventSubNumber>>deviceId>>eventType>>eventId;

                    if(eventType==etAction)
                        hy103Cpu->lstAction.append(eventId);
                    else
                        hy103Cpu->lstAlarm.append(eventId);
                }

                ds>>bNeedAnalysis>>deviceId;*/
            }
            break;
        }

        case tfcParmReadDevProtocol:
        {
            commandNotify=true;
            m_bcommandStatus=true;
            QByteArray dataTmp=data.mid(1);
            QBuffer bufParm(&(dataTmp));
            bufParm.open(QBuffer::ReadOnly);
            QDataStream ds(&bufParm);

            qDeleteAll(gDeviceProtocol);
            gDeviceProtocol.clear();

            DeviceProtocol* protocol;
            qint32 count;

            ds>>count;

            for (int i=0;i<count;i++)
            {
                protocol=new DeviceProtocol;
                ds>>protocol->id>>protocol->devNode>>protocol->type;
                gDeviceProtocol.append(protocol);
            }

            break;
        }

        case tfcMonHy103BasicInfoEth0:
        case tfcMonHy103UdpEth0:
        case tfcMonHy103TcpSendEth0:
        case tfcMonHy103TcpRecvEth0:
        case tfcMonHy103BasicInfoEth1:
        case tfcMonHy103UdpEth1:
        case tfcMonHy103TcpSendEth1:
        case tfcMonHy103TcpRecvEth1:
        case tfcMonCan0BasicInfo:
        case tfcMonCan0Send:
        case tfcMonCan0Recv:
        case tfcMonCan1BasicInfo:
        case tfcMonCan1Send:
        case tfcMonCan1Recv:
        {
            emit monitorData(data);
            break;
        }

        case tfcSectorList:
        {
            QByteArray dataTmp=data.mid(1);
            QBuffer bufParm(&(dataTmp));
            bufParm.open(QBuffer::ReadOnly);
            QDataStream ds(&bufParm);

            ds>>gactiveSector;
            ds>>glstSector;

            commandNotify=true;
            m_mutex.lock();
            m_bcommandStatus=true;
            m_mutex.unlock();
            break;
        }

        case tfcBasicStatus:
        {
            commandNotify=false;
            break;
        }

        case tfcConfirm:
        {
            commandNotify=true;
            qint8 status=data.at(1);
            m_mutex.lock();
            m_bcommandStatus=status;
            m_mutex.unlock();
            break;
        }
    }

    if(commandNotify)
    {
        m_wait.wakeAll();
    }
}

bool TargetManager::doCommand(tgtFuncCode funcCode,const QByteArray& data)
{
    QByteArray cmd;
    cmd.append((char)funcCode);

    QByteArray dataTmp;
    QBuffer bufParm(&(dataTmp));
    bufParm.open(QBuffer::WriteOnly);
    QDataStream ds(&bufParm);

    switch(funcCode)
    {
        case tfcParmWriteHardware:
        {
            ds<<ghardware.eth0Mac
              <<ghardware.eth0Ip
              <<ghardware.eth0NetMask
              <<ghardware.eth1Mac
              <<ghardware.eth1Ip
              <<ghardware.eth1NetMask
              <<ghardware.can0Bitrate
              <<ghardware.can1Bitrate
              <<ghardware.switchAddr
              <<ghardware.switchType
              <<ghardware.srl1Bitrate
              <<ghardware.srl1Charbits
              <<ghardware.srl1stopbits
              <<ghardware.srl1Parity
              <<ghardware.srl2Bitrate
              <<ghardware.srl2Charbits
              <<ghardware.srl2stopbits
              <<ghardware.srl2Parity
              <<ghardware.srl3Bitrate
              <<ghardware.srl3Charbits
              <<ghardware.srl3stopbits
              <<ghardware.srl3Parity
              <<ghardware.srl4Bitrate
              <<ghardware.srl4Charbits
              <<ghardware.srl4stopbits
              <<ghardware.srl4Parity;
            break;
        }

        case tfcParmWriteDevice:
        {
            ds<<(qint8)gCanDevice;
            ds<<gDevice.size();

            QList<quint32> deviceIds=gDevice.keys();
            quint32 devId;
            DevicePoint* point;
            for(int i=0;i<deviceIds.size();i++)
            {
                devId=deviceIds[i];
                ds<<devId;
                ds<<gDevice.value(devId);
                point=gPoints.value(devId);
                ds<<point->lstAi
                    <<point->lstDi
                    <<point->lstPi
                    <<point->lstDo
                    <<point->lstAo
                    <<point->lstAction
                    <<point->lstAlarm;
                /*
                ds<<(point->lstAi.size()+point->lstDi.size()+point->lstPi.size()
                     +point->lstDo.size()+point->lstAction.size()+point->lstAlarm.size());

                for(int j=0;j<point->lstAi.size();j++)
                {
                    ds<<pvAi<<point->lstAi[j];
                }

                for(int j=0;j<point->lstDi.size();j++)
                {
                    ds<<pvDi<<point->lstDi[j];
                }

                for(int j=0;j<point->lstPi.size();j++)
                {
                    ds<<pvPi<<point->lstPi[j];
                }

                for(int j=0;j<point->lstDo.size();j++)
                {
                    ds<<pvDo<<point->lstDo[j];
                }

                for(int j=0;j<point->lstAction.size();j++)
                {
                    ds<<pvAction<<point->lstAction[j];
                }

                for(int j=0;j<point->lstAlarm.size();j++)
                {
                    ds<<pvAlarm<<point->lstAlarm[j];
                }*/
            }
            break;
        }

        case tfcParmWriteHy103:
        {
            ds<<(qint8)gCanDevice;

            ds<<gHy103Cpu.size();
            Hy103Cpu* cpu;
            quint32 cpuId;
            QList<quint32> hy103CpuIds=gHy103Cpu.keys();

            for(int i=0;i<hy103CpuIds.size();i++)
            {
                cpuId=hy103CpuIds[i];

                ds<<cpuId;
                cpu=gHy103Cpu.value(cpuId);

                ds<<cpu->devId<<1
                    <<cpu->lstAi
                    <<cpu->lstDi
                    <<cpu->lstPi
                    <<cpu->lstDo
                    <<cpu->lstAo
                    <<cpu->lstAction
                    <<cpu->lstAlarm;
                /*
                ds<<cpu->lstAi.size();
                for(int j=0;j<cpu->lstAi.size();j++)
                {
                    ds<<cpu->devId<<cpu->lstAi[j];
                }

                ds<<cpu->lstDi.size();
                for(int j=0;j<cpu->lstDi.size();j++)
                {
                    ds<<cpu->devId<<cpu->lstDi[j];
                }

                ds<<cpu->lstPi.size();
                for(int j=0;j<cpu->lstPi.size();j++)
                {
                    ds<<cpu->devId<<cpu->lstPi[j];
                }

                ds<<cpu->lstAction.size()+cpu->lstAlarm.size();

                for(int j=0;j<cpu->lstAction.size();j++)
                {
                    ds<<j+1<<cpu->devId<<(quint32)etAction<<cpu->lstAction[j];
                }

                for(int j=0;j<cpu->lstAlarm.size();j++)
                {
                    ds<<j+1<<cpu->devId<<(quint32)etAlarm<<cpu->lstAlarm[j];
                }

                ds<<true<<cpu->devId;*/
            }
            break;
        }

        case tfcParmWriteDevProtocol:
        {
            ds<<gDeviceProtocol.size();
            for(int i=0;i<gDeviceProtocol.size();i++)
            {
                ds<<gDeviceProtocol[i]->id<<gDeviceProtocol[i]->devNode<<gDeviceProtocol[i]->type;
            }
            break;
        }

        case tfcMonHy103Eth0:
        case tfcMonHy103Eth1:
        case tfcMonCan0:
        case tfcMonCan1:
        {
            ds<<(qint8)(data.at(0));
            break;
        }

        case tfcChangeSector:
        {
            ds<<QString(data);
            break;
        }

        default:
            break;
    }

    bufParm.close();

    cmd.append(dataTmp);

    m_bcommandStatus=false;

    emit sigCommand(cmd);

    bool bret=false;

    m_mutex.lock();
    if(m_bcommandStatus)
    {
        m_mutex.unlock();
        return true;
    }
    if(m_wait.wait(&m_mutex,3000))
    {
        bret=m_bcommandStatus;
    }

    m_mutex.unlock();
    return bret;
}

////////////////////////////////////////////////////////////////////////////////
// Target

Target::Target(const QString& ip,quint16 port,QObject *parent) :
    m_ip(ip),m_port(port),QObject(parent)
{
    m_server=NULL;
    m_bconnect=false;
}

Target::~Target()
{
    if(m_bconnect)
    {
        m_server->disconnectFromHost();
        m_server->waitForDisconnected();
        m_server->deleteLater();
    }
}

void Target::init()
{
    m_server=new QTcpSocket(this);
    m_server->connectToHost(QHostAddress(m_ip),m_port);
    if(!m_server->waitForConnected(1000))
    {
        delete m_server;
        m_server=NULL;
        return;
    }

    m_bconnect=true;

    connect(m_server,SIGNAL(readyRead()),this,SLOT(processRecv()));
    connect(m_server,SIGNAL(disconnected()),this,SLOT(processDisconnect()));
}

void Target::sendCmd(QByteArray data)
{
    qint32 dataLeft=data.size();
    const char* pdata=data.data();
    char sendBuf[1024];

    sendBuf[0]='K';
    sendBuf[1]='_';
    sendBuf[2]='D';
    sendBuf[3]='E';
    sendBuf[4]='B';
    sendBuf[5]='U';
    sendBuf[6]='G';

    while(dataLeft)
    {
        if(dataLeft>MAX_FRAME_LEN)
        {
            sendBuf[7]=MAX_FRAME_LEN&0xFF;
            sendBuf[8]=(0x80|((MAX_FRAME_LEN&0xFF00)>>8));
            memcpy(sendBuf+9,pdata,MAX_FRAME_LEN);
            m_server->write(sendBuf,MAX_FRAME_LEN+9);
            m_server->waitForBytesWritten();
            pdata+=MAX_FRAME_LEN;
            dataLeft-=MAX_FRAME_LEN;
        }
        else
        {
            sendBuf[7]=dataLeft&0xFF;
            sendBuf[8]=((dataLeft&0xFF00)>>8);
            memcpy(sendBuf+9,pdata,dataLeft);
            m_server->write(sendBuf,dataLeft+9);
            m_server->waitForBytesWritten();
            break;
        }
    }
}

void Target::processRecv()
{
    while(m_server->bytesAvailable())
    {
        if(m_server->bytesAvailable()<9)
            return;

        m_server->read((char*)m_recvBuf,9);

        if(m_recvBuf[0]=='K'&&
                m_recvBuf[1]=='_'&&
                m_recvBuf[2]=='D'&&
                m_recvBuf[3]=='E'&&
                m_recvBuf[4]=='B'&&
                m_recvBuf[5]=='U'&&
                m_recvBuf[6]=='G')
        {
            m_frameLen=m_recvBuf[7]+m_recvBuf[8]*0x100;

            QByteArray dataTmp;
            dataTmp=m_server->read(m_frameLen&0x7FFF);
            if(dataTmp.size()!=(m_frameLen&0x7FFF))
            {
                m_server->readAll();
                m_data.clear();
                m_frameLen=0;
                return;
            }

            m_data.append(dataTmp);

            if(!(m_frameLen&0x8000))
            {
                dataTmp=m_data;
                emit sigData(dataTmp);
                m_data.clear();
            }
        }
        else
        {
            m_server->readAll();
            m_data.clear();
            m_frameLen=0;
            return;
        }
    }
}

void Target::processDisconnect()
{
    m_server->close();
    m_server->deleteLater();
    m_bconnect=false;
    emit sigDisconnect();
}
